#include <iostream>
#include <cmath>
#include "biom.h"
#include <set>
#include <vector>

#define VOID 0
#define WHITE 1
#define BLACK -1

using namespace biom;

void initMap(matrix<int> &obj)
{
    obj.block.clear();
    for (size_t i = 0; i < obj.row * obj.column; i++)
    {
        obj.block.push_back(VOID);
    }
}

void printMap(const matrix<int> &obj)
{
    for (size_t i = 0; i < obj.block.size(); i++)
    {
        char bit;
        if (obj.block[i] == 0)
            bit = ' ';
        if (obj.block[i] > 0)
            bit = 'O';
        if (obj.block[i] < 0)
            bit = 'X';

        printf("%c ", bit);
        if (i != 0 && (i + 1) % (obj.column) == 0)
            printf("\n");
    }
}

int getRound(matrix<int> &A, int r, int c)
{
    int sum = 0;
    for (int i = r - 1; i <= r + 1; i++)
    {
        for (int j = c - 1; j <= c + 1; j++)
        {
            if (i >= 0 && j >= 0 && i < A.row && j < A.column)
            {
                sum += A(i, j);
            }
        }
    }
    sum -= A(r, c); // Remove cenntral value
    return sum;
}

void updateMap(matrix<int> &A) // Core Algorithm Design
{
    matrix<int> REC = A;
    for (int i = 0; i < A.row; i++)
    {
        for (int j = 0; j < A.column; j++)
        {
            int n = getRound(A, i, j);

            if (n == 0)
            {
                if (fabs(A(i, j)) <= 9)
                    REC(i, j) = A(i, j);
                else
                    REC(i, j) = VOID;
            }

            if (n > 0)
            {
                if (A(i, j) == 0)
                {
                    REC(i, j) = WHITE;
                }

                if (A(i, j) > 0)
                {
                    if (fabs(n) >= 4 && fabs(n) <= 9)
                        REC(i, j) = A(i, j) + 1;
                    else
                        REC(i, j) = A(i, j) - 1;
                }

                if (A(i, j) < 0)
                {
                    (-A(i, j) < fabs(n)) ? REC(i, j) = VOID : REC(i, j) = A(i, j) + 1;
                }
            }

            if (n < 0)
            {
                if (A(i, j) == 0)
                {
                    REC(i, j) = BLACK;
                }

                if (A(i, j) < 0)
                {
                    if (fabs(n) >= 4 && fabs(n) <= 9)
                        REC(i, j) = A(i, j) - 1;
                    else
                        REC(i, j) = A(i, j) + 1;
                }

                if (A(i, j) > 0)
                {
                    (-A(i, j) > fabs(n)) ? REC(i, j) = VOID : REC(i, j) = A(i, j) - 1;
                }
            }

            if (fabs(A(i, j)) >= 9)
                REC(i, j) = VOID;

            // if (fabs(n) >= 4)
            // {
            //     if (A(i, j) > 0)
            //     {
            //         REC(i, j) = -REC(i, j) + 1;
            //     }
            //     if (A(i, j) < 0)
            //     {
            //         REC(i, j) = -REC(i, j) - 1;
            //     }
            // }
        }
    }
    A = REC;
}

// int getWHITE(matrix<int> &A)
// {
//     int cnt = 0;
//     for (size_t i = 0; i < A.block.size(); i++)
//     {
//         if (A.block[i] > 0)
//             cnt++;
//     }
//     return cnt;
// }

// int getBLACK(matrix<int> &A)
// {
//     int cnt = 0;
//     for (size_t i = 0; i < A.block.size(); i++)
//     {
//         if (A.block[i] < 0)
//             cnt++;
//     }
//     return cnt;
// }

matrix<int> compress(const matrix<int> &A)
{
    matrix<int> tmp(A.row, A.column);
    for (size_t i = 0; i < A.row; i++)
    {
        for (size_t j = 0; j < A.column; j++)
        {
            int s = A.block[i * A.column + j];
            if (s > 0)
                tmp.block.push_back(1);
            if (s < 0)
                tmp.block.push_back(-1);
            if (s == 0)
                tmp.block.push_back(0);
        }
    }
    return tmp;
}

int main()
{
    int N;
    std::cout << "N = ";
    std::cin >> N;
    matrix<int> map(N, N);
    initMap(map);

    map(0, N - 1) = WHITE;
    map(N - 1, 0) = WHITE;
    map(0, 0) = BLACK;
    map(N - 1, N - 1) = BLACK;

    printMap(map);
    system("pause");

    // char key = 'Y';
    size_t count = 0;
    std::vector<matrix<int>> list;

    while (1)
    {
        // std::cout << "Continue? (Y/n): ";
        // std::cin >> key;
        // std::cout << std::endl;
        // system("pause");

        auto m_c = compress(map);
        // auto m_c = map;

        std::vector<matrix<int>>::iterator it = std::find(list.begin(), list.end(), m_c);
        if (it == list.end())
        {
            list.push_back(m_c);
            updateMap(map);
            std::cout << "\n[Map]: " << count << std::endl;
            printMap(m_c);
            count++;
            continue;
        }
        else
        {
            std::cout << "\n[Over]=> " << count - 1 << std::endl;
            printMap(m_c);
            break;
        }
    }

    return 0;
}